package com.gitee.hermer.engine.jars.app.sdk.proxy;



import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.springframework.aop.SpringProxy;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;

import com.gitee.hermer.boot.jee.commons.exception.ErrorCode;
import com.gitee.hermer.boot.jee.commons.exception.PaiUException;
import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;
import com.gitee.hermer.boot.jee.commons.verify.Assert;
import com.gitee.hermer.engine.jars.core.annotate.EngineAppReference;
import com.gitee.hermer.engine.jars.core.app.domain.EngineAppContext;
import com.gitee.hermer.engine.jars.core.domain.EngineConstant;
import com.gitee.hermer.engine.jars.core.execute.manage.IEngineExecutePoolManager;

public class ExecuteProxy extends UtilsContext implements InvocationHandler, Serializable,SpringProxy {

	private final ApplicationContext applicationContext; //self Context

	public ExecuteProxy(ApplicationContext applicationContext){
		this.applicationContext = applicationContext;
	}

	public static boolean isProxyClass(Object cl){
		try{
			if(Proxy.isProxyClass(cl.getClass())){
				Field h = cl.getClass().getSuperclass().getDeclaredField("h");
				h.setAccessible(true);  
				if(h.get(cl) instanceof ExecuteProxy){
					return true;
				}
			}
		}catch (Exception e) {
			EngineConstant.LOGGER.error(e.getMessage(),e);
		}
		return false;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(method.getName().equals("toString")){
			return this.toString();
		}else if(method.getName().equals("equals")){
			return this.equals(args[0]);
		}else{
			final AnnotationAttributes metadataAttributes = AnnotatedElementUtils.getMergedAnnotationAttributes(method, EngineAppReference.class);
			if(metadataAttributes != null){

				String appName = metadataAttributes.getString(EngineConstant.ANNOTATE_FIELD_NAME_APP_NAME);
				String appVersion = metadataAttributes.getString(EngineConstant.ANNOTATE_FIELD_NAME_APP_VERSION);
				String workMethod = metadataAttributes.getString(EngineConstant.ANNOTATE_FIELD_NAME_WORK_METHOD);
				String workVersion = metadataAttributes.getString(EngineConstant.ANNOTATE_FIELD_NAME_WORK_VERSION);

				String template = "@EngineReference字段{}不可为空";

				Assert.hasTextCode(appName, ErrorCode.SYSTEM_ERROR,StringUtils.format(template, EngineConstant.ANNOTATE_FIELD_NAME_APP_NAME));
				Assert.hasTextCode(appVersion, ErrorCode.SYSTEM_ERROR,StringUtils.format(template, EngineConstant.ANNOTATE_FIELD_NAME_APP_VERSION));
				Assert.hasTextCode(workMethod, ErrorCode.SYSTEM_ERROR,StringUtils.format(template, EngineConstant.ANNOTATE_FIELD_NAME_WORK_METHOD));
				Assert.hasTextCode(workVersion, ErrorCode.SYSTEM_ERROR,StringUtils.format(template, EngineConstant.ANNOTATE_FIELD_NAME_WORK_VERSION));

				IEngineExecutePoolManager executePoolManager = applicationContext.getBean(EngineAppContext.class).getParentContext().getBean(IEngineExecutePoolManager.class);
				return executePoolManager.execute(appName,appVersion,workMethod,workVersion,args);
			}
			throw new PaiUException(ErrorCode.SYSTEM_ERROR, "Not Find @EngineAppReference AnnotationAttributes");
		}
	}

}
